package com.example.demo.utils;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.HashMap;

@Slf4j
@SuppressWarnings("all")
public class ReflectUtil {

    /**
     * 定义需要判断的数据类型
     */
    private static final String BYTE = "class java.lang.Byte";
    private static final String SHORT = "class java.lang.Short";
    private static final String INTEGER = "class java.lang.Integer";
    private static final String LONG = "class java.lang.Long";
    private static final String FLOAT = "class java.lang.Float";
    private static final String DOUBLE = "class java.lang.Double";
    private static final String BOOLEAN = "class java.lang.Boolean";
    private static final String CHARACTER = "class java.lang.Character";
    private static final String STRING = "class java.lang.String";
    private static final String DATE = "class java.util.Date";
    private static final String LOCAL_DATETIME = "class java.time.LocalDateTime";
    private static final String LIST = "class java.util.List";
    private static final HashMap<String, Object> HASH_MAP;

    /**
     * 将数据装入HASH_MAP集合，下面判断类型时使用
     */
    static {
        HASH_MAP = new HashMap<>();
        HASH_MAP.put(BYTE, null);
        HASH_MAP.put(SHORT, null);
        HASH_MAP.put(INTEGER, null);
        HASH_MAP.put(LONG, null);
        HASH_MAP.put(FLOAT, null);
        HASH_MAP.put(DOUBLE, null);
        HASH_MAP.put(BOOLEAN, null);
        HASH_MAP.put(CHARACTER, null);
        HASH_MAP.put(STRING, null);
        HASH_MAP.put(DATE, null);
        HASH_MAP.put(LOCAL_DATETIME, null);
        HASH_MAP.put(LIST, null);
    }


    /**
     * @description:        将传入的对象中的Double类型的字段都保留两位小数
     * @param model         传入的对象
     * @return void         无返回
     * @Author：LJP
     * @date: 2021/6/23 15:13

     */
    public static void twoDecimalPlacesByReflect(Object model,int place) throws Exception {
        // 获取实体类的所有属性，返回Field数组
        Field[] field = model.getClass().getDeclaredFields();
        // 遍历所有属性
        for (int j = 0; j < field.length; j++) {
            // 获取属性的名字
            String name = field[j].getName();
            // 将属性的首字符大写，方便构造get，set方法
            name = name.substring(0, 1).toUpperCase() + name.substring(1);
            // 获取属性的类型
            String type = field[j].getGenericType().toString();
            // 如果type是类类型，则前面包含"class "，后面跟类名
//            log.info("属性为：" + name);
            if (HASH_MAP.containsKey(type)) {
                typeJudgment(field[j],type, model, name,place);
            }

        }
    }

    /**
     * @description:        通过反射获取字段以及get()、set()方法并对数据进行处理
     * @param field         传入的字段
     * @param dataType      字段类型
     * @param model         字段所属对象
     * @param name          字段名
     * @return void
     * @Author：LJP
     * @date: 2021/6/23 15:14

     */
    public static void typeJudgment(Field field,String dataType, Object model, String name,int place) throws Exception {
        //放开字段权限
        field.setAccessible(true);
        //获得get()方法
        Method m = model.getClass().getMethod("get" + name);
        //获得要强转的类型
        Class<?> aClass = Class.forName(dataType.substring(6));
        //获得字段类型 -> String类型
        String charStr = dataType.substring(dataType.lastIndexOf(".") + 1);
        //通过get()方法获得字段值
        Object invoke = m.invoke(model);
        //字段强转
        Object castType = aClass.cast(invoke);
        //如果是Double或者是Integer类型就获得set()方法并对数据进处理
        if(castType instanceof Double){
            //获得set()方法
            Method m2 = model.getClass().getMethod("set" + name,field.getType());
            //处理字段值
            Double aDouble = transformDouble(castType,place);
            //使用set()方法重新给字段赋值
            field.set(model,aDouble);
        }
    }

    /**
     * @description:        将传入的数据保留两位小数
     * @param d             传入的数据
     * @return Double       保留两位小数后返回
     * @Author：LJP
     * @date: 2021/6/23 15:17

     */
    public static Double transformDouble(Object d,int placeNum){
        String place = "";
        Double num = (Double) d;
        DecimalFormat df =null;
        if (placeNum==0){
            df = new DecimalFormat("######0.00");
        }else {
            for (int i = 0; i < placeNum; i++) {
                place+="0";
            }
            df = new DecimalFormat("######0."+place);
        }
        String format = df.format(num);
        return Double.valueOf(format);
    }

    public static Double transformDouble(Double num,int placeNum){
        String place = "";
        DecimalFormat df =null;
        if (placeNum==0){
            df = new DecimalFormat("######0.00");
        }else {
            for (int i = 0; i < placeNum; i++) {
                place+="0";
            }
            df = new DecimalFormat("######0."+place);
        }
        String format = df.format(num);
        return Double.valueOf(format);
    }
}
